package it.uniroma2;

import it.uniroma2.cloud.PROVIDER;
import it.uniroma2.cloud.ProviderFactory;
import it.uniroma2.cloud.util.ProviderHelperFactory;
import it.uniroma2.jcloudstests.Command;
import it.uniroma2.monitor.client.DateUtils;
import it.uniroma2.monitor.client.MetricRequest;
import it.uniroma2.monitor.client.MetricResult;
import it.uniroma2.monitor.client.MetricValue;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.StringReader;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;

import org.jclouds.aws.reference.AWSConstants;
import org.joda.time.DateTime;
import org.joda.time.DateTimeZone;
import org.joda.time.format.DateTimeFormat;

import au.com.bytecode.opencsv.CSVReader;

import com.google.common.util.concurrent.Monitor;
import com.sun.jersey.api.client.Client;
import com.sun.jersey.api.client.ClientResponse;
import com.sun.jersey.api.client.WebResource;

public class MonitorClient {

	private static MonitorClient monitorClient;
	private String host;

	private MonitorClient(String host) {
		this.host = host;
	}

	public static MonitorClient getInstance() {
		if (monitorClient == null) {
			Command awsCommand = new Command(
					ProviderFactory.createComputeService(PROVIDER.AWS_EC2),
					ProviderHelperFactory.getProviderHelper(PROVIDER.AWS_EC2));
			monitorClient = new MonitorClient(awsCommand.getMonitoringAddress());
		}
		return monitorClient;
	}

	private String build(MetricRequest metricRequest) {
		StringBuffer url = new StringBuffer();
		url.append("http://")
				.append(host)
				.append("/render/?target=")
				.append(metricRequest.getMetricName())
				.append("&from=")
				.append(DateUtils.fromDateTimeToRequest(metricRequest.getFrom()))
				.append("&until=")
				.append(DateUtils.fromDateTimeToRequest(metricRequest
						.getUntil())).append("&format=csv");
		return url.toString();
	}

	public MetricResult makeRequest(MetricRequest metricRequest) {
		MetricResult metricResult = null;
		try {
			Client client = Client.create();
			String url = build(metricRequest);
			System.out.println(url);
			WebResource webResource = client.resource(url);
			ClientResponse response = webResource.accept("application/csv")
					.get(ClientResponse.class);
			if (response.getStatus() != 200) {
				throw new RuntimeException("Failed : HTTP error code : "
						+ response.getStatus());
			}
			String output = response.getEntity(String.class);
			CSVReader reader = new CSVReader(new StringReader(output), ',');
			metricResult = new MetricResult(metricRequest.getMetricName());
			String[] nextLine;
			while ((nextLine = reader.readNext()) != null) {
				Double d;
				if ("".equals(nextLine[2]))
					continue;
				else
					d = Double.parseDouble(nextLine[2]);
				MetricValue metricValue = new MetricValue(
						DateUtils.fromCSVToDateTime(nextLine[1]), d);
				metricResult.add(metricValue);
			}
			reader.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
		return metricResult;
	}

	public String buildComplex(List<MetricRequest> metricRequests,
			String title, String vTitle, String other) throws UnsupportedEncodingException {
		StringBuffer url = new StringBuffer();
		url.append("http://").append(host).append("/render/?");
		for (MetricRequest metricRequest : metricRequests) {
			url.append("&target=" + URLEncoder.encode(metricRequest.getMetricName(), "UTF-8"));
		}
		url.append("&from=")
				.append(DateUtils.fromDateTimeToRequest(metricRequests.get(0)
						.getFrom()))
				.append("&until=")
				.append(DateUtils.fromDateTimeToRequest(metricRequests.get(0)
						.getUntil())).append("&format=svg")
				.append("&title=" + title).append("&vtitle=" + vTitle)
				.append(other);
		return url.toString();
	}

	public void makeRequestComplex(List<MetricRequest> metricRequests,
			String title, String vTitle, String other) {
		try {
			String titleEncoded = URLEncoder.encode(title, "UTF-8");
			String vtitleEncoded = URLEncoder.encode(vTitle, "UTF-8");
			Client client = Client.create();
			String url = buildComplex(metricRequests, titleEncoded,
					vtitleEncoded, other);
			System.out.println(url);
			WebResource webResource = client.resource(url);
			ClientResponse response = webResource.accept("image/svg+xml").get(
					ClientResponse.class);
			if (response.getStatus() != 200) {
				throw new RuntimeException("Failed : HTTP error code : "
						+ response.getStatus());
			}
			byte[] buffer = new byte[8 * 1024];

			InputStream input = response.getEntityInputStream();
			try {
				String fielTitle = title.replace('_', '-').replace(' ', '-').replace('%', '-');
				OutputStream output = new FileOutputStream(fielTitle + ".svg");
				try {
					int bytesRead;
					while ((bytesRead = input.read(buffer)) != -1) {
						output.write(buffer, 0, bytesRead);
					}
				} finally {
					output.close();
				}
			} finally {
				input.close();
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		// http://ec2-23-22-114-15.compute-1.amazonaws.com/render/?target=Client-ip-10-196-118-172.it.uniroma2.HttpClient.duration.meanRate&from=18:10_20130223&until=18:30_20130223"&format=csv
		DateTime from = new DateTime(2014, 4, 13, 15, 40, DateTimeZone.UTC);
		DateTime until = new DateTime(2014, 4, 13, 22, 55, DateTimeZone.UTC);

		// LOAD
		MetricRequest req1 = new MetricRequest(
				"post.aggregated.OPENSTACK.imagetranscoder.monitor.load.loadAverage-1Min",
				from, until);
		MetricRequest req2 = new MetricRequest(
				"post.aggregated.AWS_EC2.imagetranscoder.monitor.load.loadAverage-1Min",
				from, until);
		MetricRequest req0 = new MetricRequest(
				"post.aggregated.ALL.imagetranscoder.monitor.load.loadAverage-1Min",
				from, until);
		ArrayList<MetricRequest> reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req2);
		reqs.add(req0);

		MonitorClient monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs,
						"loadAverage-1Min, AWS_EC2 vs Openstack", "Load (%)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");

		// Latency
		req1 = new MetricRequest("master.controller.AWS_EC2.latency", from,
				until);
		req2 = new MetricRequest("master.controller.OPENSTACK.latency", from,
				until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req2);

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "Latency, AWS_EC2 vs Openstack",
						"Latency (ms)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");

		// Moving Average
		//summarize(*.aggregated.AWS_EC2.imagetranscoder.monitor.memory.memory-used-percent,"2min")
		req1 = new MetricRequest("master.controller.AWS_EC2.movingAverageLoad",
				from, until);
		req2 = new MetricRequest("master.controller.OPENSTACK.movingAverageLoad",
				from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req2);

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "MovingAverage Load, AWS_EC2 vs Openstack",
						"Load (%)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0&minXStep=0");
		
		
		// Request vs Service
		req1 = new MetricRequest("post.aggregated.ALL.imagetranscoder.requestRate.m1_rate",
				from, until);
		req0 = new MetricRequest("post.aggregated.ALL.imagetranscoder.serviceRate.m1_rate", from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req0);

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "Request Rate vs Service Rate",
						"Request per second",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");
		
		//Processing duration
		req1 = new MetricRequest("post.aggregated.AWS_EC2.imagetranscoder.processing-duration.mean",
				from, until);
		req0 = new MetricRequest("post.aggregated.OPENSTACK.imagetranscoder.processing-duration.mean", from, until);
		req2 = new MetricRequest("post.aggregated.ALL.imagetranscoder.processing-duration.mean", from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req0);
		reqs.add(req2);
		

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "Processing Duration, AWS_EC2 vs Openstack",
						"Processing duration (ms)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");
		
		//CPU
		//post.aggregated.AWS_EC2.imagetranscoder.monitor.cpu.cpu-process-percent
		req1 = new MetricRequest("post.aggregated.AWS_EC2.imagetranscoder.monitor.cpu.cpu-process-percent",
				from, until);
		req0 = new MetricRequest("post.aggregated.OPENSTACK.imagetranscoder.monitor.cpu.cpu-process-percent", from, until);
		req2 = new MetricRequest("post.aggregated.ALL.imagetranscoder.monitor.cpu.cpu-process-percent", from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req0);
		reqs.add(req2);
		

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "CPU process %, AWS_EC2 vs Openstack",
						"CPU (%)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");
		
		//How many instances
		//master.controller.OPENSTACK.howManyInstances
		//post.aggregated.ALL.controller.howManyInstances
		req1 = new MetricRequest("master.controller.AWS_EC2.howManyInstances",
				from, until);
		req0 = new MetricRequest("master.controller.OPENSTACK.howManyInstances", from, until);
		req2 = new MetricRequest("post.aggregated.ALL.controller.howManyInstances", from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req0);
		reqs.add(req2);
		

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "How many instances Instances, AWS_EC2 vs Openstack ",
						"# Instances per Cloud Provider",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0&yMax=10");
		//Memory
		//post.aggregated.AWS_EC2.imagetranscoder.monitor.memory.memory-used-percent
		req1 = new MetricRequest("post.aggregated.AWS_EC2.imagetranscoder.monitor.memory.memory-used-percent",
				from, until);
		req0 = new MetricRequest("post.aggregated.OPENSTACK.imagetranscoder.monitor.memory.memory-used-percent", from, until);
		req2 = new MetricRequest("post.aggregated.ALL.imagetranscoder.monitor.memory.memory-used-percent", from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req0);
		reqs.add(req2);
		

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "Memory used %, AWS_EC2 vs Openstack",
						"Memory used (%)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");
		
		//Request Rate
		//*.aggregated.AWS_EC2.imagetranscoder.requestRate.m1_rate
		req1 = new MetricRequest("post.aggregated.AWS_EC2.imagetranscoder.requestRate.m1_rate",
				from, until);
		req0 = new MetricRequest("post.aggregated.OPENSTACK.imagetranscoder.requestRate.m1_rate", from, until);
		req2 = new MetricRequest("post.aggregated.ALL.imagetranscoder.requestRate.m1_rate", from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		reqs.add(req0);
		reqs.add(req2);
		

		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "Request Rate, AWS_EC2 vs Openstack",
						"Request per second",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");

		//Client duration
		//*.client.duration.mean
		req1 = new MetricRequest("*.client.duration.mean",
				from, until);
		reqs = new ArrayList<MetricRequest>();
		reqs.add(req1);
		monitorClient = MonitorClient.getInstance();
		monitorClient
				.makeRequestComplex(reqs, "Client duration (Response time)",
						"Response Time (ms)",
						"&lineMode=connected&margin=25&lineWidth=1.8&height=600&width=800&fontBold=true&fontSize=12&yMin=0");
	}

}
